/*      Copyright 2002 Arizona Board of regents on behalf of
 *                  The University of Arizona
 *                     All Rights Reserved
 *         (USE & RESTRICTION - Please read COPYRIGHT file)
 *
 *  Version    : DEVSJAVA 2.7
 *  Date       : 08-15-02
 */

package genDevs.simulation.realTime;

import java.util.*;
import genDevs.modeling.*;
import genDevs.simulation.*;
import GenCol.*;
import util.*;

/**
 * A coupled-coordinator meant to serve as a child or descendent of a
 * TunableCoordinator, presiding over a group of sibling components
 * at one level of the tree of components that makes up a simulation model.
 */
public class TunableCoupledCoordinator extends coupledCoordinator
{
    /**
     * An object interested in events generated by this coordinator.
     * Note that this listener is expecting to be passed down to all
     * subordinate coordinators and simulators.
     */
    protected Listener listener;

    /**
     * Constructor.
     *
     * @param   digraph     The digraph model over which this coordinator
     *                      should preside.
     * @param   listener_   See member variable accessed.
     */
    public TunableCoupledCoordinator(digraph digraph, Listener listener_)
    {
        super(digraph, false);

        listener = listener_;

        constructorHook1();

        setSimulators();
        informCoupling();
    }

    /**
     * A hook used by the simView package.
     */
    protected void constructorHook1() {}

    /**
     * Creates a simulator for the given devs component,
     * and associates that simulator with this coordinator.
     *
     * @param   devs        The devs component for which to create a simulator.
     */
    public void addSimulator(IOBasicDevs devs)
    {
        // get the simulator created for the given component
        coupledSimulator simulator = createSimulator(devs);

        addSimulatorHook1(simulator);

        simulatorCreated(simulator, devs);
    }

    /**
     * A hook used by the simView package.
     *
     * @param   simulator   The newly created simulator.
     */
    protected void addSimulatorHook1(coupledSimulator simulator) {}

    /**
     * Creates a simulator for the given devs component.
     *
     * @param   devs        The devs component for which to create a simulator.
     */
    protected coupledSimulator createSimulator(IOBasicDevs devs)
    {
        // if deferring to a hook doesn't produce a simulator
        // for the given component
        coupledSimulator simulator = createSimulatorHook1(devs);
        if (simulator == null) {
            // create a coupled simulator for it
            simulator = new coupledSimulator(devs);
        }

        // initialize the simulator
        simulator.setRootParent(this);
        simulator.initialize();

        return simulator;
    }

    /**
     * A hook used by the simView package.
     *
     * @param   devs        The devs component for which to create a simulator.
     */
    protected coupledSimulator createSimulatorHook1(IOBasicDevs devs) {return null;}

    /**
     * Creates a tunable-coupled-coordinator to preside over the given
     * coupled component (which is assumed to be a child of this
     * coordinator's digraph).
     *
     * @param   comp     The coupled component for which to create a coordinator.
     */
    public void addCoordinator(Coupled digraph)
    {
        // if deferring to a hook doesn't produce a coordinator for the
        // given digraph
        TunableCoupledCoordinator coordinator = addCoordinatorHook1(
            (digraph)digraph);
        if (coordinator == null) {
            // create a coordinator for the given digraph
            coordinator = new TunableCoupledCoordinator((digraph)digraph,
                (TunableCoupledCoordinator.Listener)listener);
        }

        coordinator.setRootParent(this);

        simulatorCreated(coordinator, digraph);
    }

    /**
     * A hook used by the simView package.
     *
     * @param   digraph        The digraph for which to create a coordinator.
     */
    protected TunableCoupledCoordinator addCoordinatorHook1(digraph digraph) {return null;}

    /**
     * Performs extra tasks at some point within the associated parent class
     * method.
     *
     * See convertInputHook1.
     */
    protected void convertMsgHook1(content oldContent, Pair coupling,
        content newContent)
    {
        convertInputHook1(oldContent, coupling, newContent);
    }

    /**
     * Performs extra tasks at some point within the associated parent class
     * method.
     *
     * @param   oldContent      The content object that existed before
     *                          its traversal of the coupling.
     * @param   coupling        The coupling traversed by the content.
     * @param   newContent      The content object as it stands now
     *                          after the traversal.
     */
    protected void convertInputHook1(content oldContent, Pair coupling,
        content newContent)
    {
        // this method must be performed only if we have a listener
        if (listener == null) return;

        // detm the component at the end of the coupling the content
        // has just travelled
        EntityInterface component = AtomicSimulatorUtil.getComponentWithName(
            (String)coupling.getKey(), modelToSim, null);
        if (component == null) {
          if(myParent!=null) component = AtomicSimulatorUtil.getComponentWithName(
                (String)coupling.getKey(), internalModelTosim,
                  (coordinator)myParent);
          else component = AtomicSimulatorUtil.getComponentWithName(
                (String)coupling.getKey(), internalModelTosim,
                  (coordinator)myRootParent);
        }

        // inform the model-view the content has crossed another coupling
        listener.couplingAddedToContentPath(oldContent,
            (devs)component, newContent.getPort().getName(),
            newContent, myCoupled.getName());
    }

    /**
     * An object interested in events generated by this coordinator.
     */
    static public interface Listener
    {
        /**
         * See identical ViewableAtomicSimulator.Listener interface method.
         */
        void couplingAddedToContentPath(content oldContent,
            devs destComponent, String destPortName,
            content newContent, String sourceComponentName);
    }
}


